package pl.com.photogetter;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;

import javax.swing.*;
import javax.swing.event.*;

/**
 * @author Piotr Maślany
 * 
 */
public class GUI
	extends JFrame
	implements Runnable, ActionListener, ChangeListener {

	public Properties properties;
	public String Version = PhotoDownloader.Version;
	public Container cp;
	public JButton sourceBrowseButton,startSortButton,exitButton,targetBrowseButton;
	public JScrollPane scrollPane;
	public JMenuItem exitAppMenuItem,setPropertiesMenuItem,usageHelpMenuItem,aboutHelpMenuItem;
	public JMenu fileMenu, helpMenu;
	public JTextArea outputTextArea;
	public JPanel middlePanel, footerPanel;
	public JFileChooser sourceFileChooser;
	public JProgressBar allProgress;
	public HashMap files;
	public Sorter imagesorter;
	public JDialog jd;
	/**
	 * This Constructor takes a properties object which should hold the global
	 * configuration as fetched from CONFIGFILE by the main class.
	 * 
	 * @param props -
	 *                    Properties from the main class.
	 */
	public GUI(Properties props) 
	{
		this.properties = props;
		this.setBounds(100,100,800,800);
	}

	private void initComponents() 
	{
		sourceFileChooser = new JFileChooser();
		sourceFileChooser.setAcceptAllFileFilterUsed(false);
		sourceFileChooser.setFileFilter(new Filter());
		sourceFileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		sourceFileChooser.setDialogTitle("Wybierz katalog źródłowy");
		
		cp = this.getContentPane();

		allProgress = new JProgressBar(JProgressBar.HORIZONTAL);
		allProgress.setStringPainted(true);
		allProgress.addChangeListener(this);
		
		startSortButton = new JButton("Przetwarzanie");
		startSortButton.setToolTipText("Rozpocznij przetwarzanie");
		startSortButton.addActionListener(this);

		exitButton = new JButton("Wyjście");
		exitButton.setToolTipText("Wyjdź z programu");
		exitButton.addActionListener(this);
		
		setJMenuBar(initMenu());

		footerPanel = new JPanel(new FlowLayout());
		footerPanel.add(startSortButton);
		footerPanel.add(exitButton);

		middlePanel = new JPanel(new BorderLayout());

		outputTextArea = new JTextArea(20, 60);
		outputTextArea.setAutoscrolls(true);
		outputTextArea.setEditable(false);
		outputTextArea.setLineWrap(true);
		scrollPane = new JScrollPane(outputTextArea);
		scrollPane.setAutoscrolls(true);
		JPanel middleNorthPanel = new JPanel(new BorderLayout());
		JPanel middleSouthPanel = new JPanel(new BorderLayout());
		
		middleSouthPanel.add(allProgress, BorderLayout.SOUTH);
		
		middlePanel.add(middleNorthPanel, BorderLayout.NORTH);
		middlePanel.add(scrollPane, BorderLayout.CENTER);
		middlePanel.add(middleSouthPanel, BorderLayout.SOUTH);

		cp.setLayout(new BorderLayout());
		cp.add(footerPanel, BorderLayout.SOUTH);
		cp.add(middlePanel, BorderLayout.CENTER);

	}

	/**
	 * This method calls the FileChooser Dialog
	 * 
	 * @param parent
	 * @return the canonical path of the choosen directory.
	 */
	protected String browseSource(Component parent) {

		int returnVal = sourceFileChooser.showDialog(parent, "Select");
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			try {
				return sourceFileChooser.getSelectedFile().getCanonicalPath();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return "Error";
			}
		} else {
			return "No file choosed";
		}
	}

	/**
	 * Initialises the Menubar
	 * 
	 * @return a JMenuBar object for inserting into a JFrame
	 */
	protected JMenuBar initMenu() {
		JMenuBar ret = new JMenuBar();

		fileMenu = new JMenu("Opcje");
		fileMenu.setMnemonic('O');

		setPropertiesMenuItem = new JMenuItem("Opcje");
		setPropertiesMenuItem.addActionListener(this);

		exitAppMenuItem = new JMenuItem("Wyjście");
		exitAppMenuItem.addActionListener(this);

		fileMenu.addSeparator();
		fileMenu.add(setPropertiesMenuItem);
		fileMenu.addSeparator();
		fileMenu.add(exitAppMenuItem);

		ret.add(fileMenu);

		helpMenu = new JMenu("Pomoc");

		usageHelpMenuItem = new JMenuItem("Jak korzystać");
		usageHelpMenuItem.addActionListener(this);

		aboutHelpMenuItem = new JMenuItem("O programie");
		aboutHelpMenuItem.addActionListener(this);

		helpMenu.add(usageHelpMenuItem);
		helpMenu.add(aboutHelpMenuItem);

		ret.add(helpMenu);
		return ret;

	}

	/**
	 * If the properties entry from the File menu is choosed this method is
	 * called and will show a Dialog for entering the Database properties.
	 * Additionally the default target directory can be set. This dialog will
	 * save the properties to the global properties file. After finishing the
	 * dialog the TextField displaying the current target directory is
	 * actualized with the value from the properties file.
	 * 
	 * @param e
	 */
	protected void setPropertiesMenuItemActionPerformed(ActionEvent e) 
	{
		PropertyWizard propsgui = new PropertyWizard(this, properties);
		propsgui.setTitle("Ustawienia");
		propsgui.setVisible(true);
				
		loadProperties(properties.getProperty("PROPERTIESFILE"));
	}

	/**
	 * This method displays public information about this Application
	 * 
	 * @param e
	 */
	protected void aboutHelpMenuItemActionPerformed(ActionEvent e) {
		String helpmessage = "";
		helpmessage = helpmessage + "\n";
		helpmessage = helpmessage + "Photo Downloader\n";
		helpmessage = helpmessage + "Program pozwala na uporządkowanie zdjęć wg dat\n";
		helpmessage = helpmessage + "zrobienia zdjęcia zapisanych w EXIF.\n";
		helpmessage = helpmessage + "Autor: Piotr Maślany\n";
		helpmessage = helpmessage + "\n";
		helpmessage = helpmessage + "Wersja: " + this.Version + "\n";
		//helpmessage =
		//	helpmessage + "<html><A HREF=\"http://www.maslany.pl\">Strona domowa</A></html>\n";

		JOptionPane.showConfirmDialog(
			this,
			helpmessage,
			"O programie",
			JOptionPane.CLOSED_OPTION,
			JOptionPane.INFORMATION_MESSAGE);

	}

	/**
	 * This message gives help on usage of this application.
	 * 
	 * @param e
	 */
	protected void usageHelpMenuItemActionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub

		String helpmessage = "Instrukcja korzystania z programu\n";
		helpmessage = helpmessage + "\n";
		helpmessage =
			helpmessage
				+ "W menu plik wybierz opcje a następnie ustaw\n";
		helpmessage = helpmessage + "<html><li>katalogi źródłowy (zawierający zdjęcia luzem lub w podkatalogach)</li>";
		helpmessage = helpmessage + "<li>docelowy, do którego mają trafić zdjęcia uporządkowane</li></html>\n";
		helpmessage =
			helpmessage
				+ "Zaznaczenie opcji 'Zagnieżdżanie pełne' powoduje, że\n";
		helpmessage = helpmessage + "w docelowym katalogu powstaje struktura katalogów odpowiednia dla\n";
		helpmessage = helpmessage + "roku, miesiąca i dnia wykonania zdjęcia \n wg wzorca YYYY -> MM -> DD -> zdjęcia z dnia \n";
		helpmessage = helpmessage + "Przetwarzanie proste porządkuje zdjęcia w katalogach nazywanych wg\n";
		helpmessage = helpmessage + "wzorca YYYY_MM_DD - w tym trybie możesz także wskazać rodzaj separatora.\n";
		helpmessage = helpmessage + "Po zapisaniu zmian w głównym oknie uruchom przetwarzanie.\n";
		JOptionPane.showConfirmDialog(
			this,
			helpmessage,
			"Instrukcja",
			JOptionPane.CLOSED_OPTION,
			JOptionPane.INFORMATION_MESSAGE);

	}

	
	/**
	 * If an Exitbutton is pressed or the corresponding menu item is choosed
	 * this method will end the application.
	 * 
	 * @param e
	 */
	protected void exitButtonActionPerformed(ActionEvent e) {
		System.exit(0);
	}

	/**
	 * If the Start Button is pressed then a new ImageSorter instance is
	 * created and the thread will be started.
	 * 
	 * @param e
	 */
	protected void startSortButtonActionPerformed(ActionEvent e) 
	{
		loadProperties(properties.getProperty("PROPERTIESFILE"));
		String source = properties.getProperty("SOURCEDIR");
		String target = properties.getProperty("PHOTODIR");
		boolean fault = false;
		if (source == null || source.equals(""))
		{
			JOptionPane.showMessageDialog(
					this,
					"Nie wskazano katalogu źródłowego",
					"Nie wskazano katalogu źródłowego",
					JOptionPane.ERROR_MESSAGE,
					null);
			fault=true;
		}
		if (!fault && (target == null || target.equals("")))
		{
			JOptionPane.showMessageDialog(
					this,
					"Nie wskazano katalogu docelowego",
					"Nie wskazano katalogu docelowego",
					JOptionPane.ERROR_MESSAGE,
					null);
			fault=true;
		}
		
		sourceDirUpdate(source);
		
		if (fault) {return;}
		outputTextArea.setText(null);
		imagesorter = new Sorter(this, properties, files);
		imagesorter.start();

	}
	
	private void sourceDirUpdate(String source) 
	{
		files = new HashMap();
		findFiles(source);
		outputTextArea.setText(null);
		allProgress.setValue(0);
		allProgress.setMaximum(files.size());
	}

	/**
	 * THis method will find all the JPEG files in the source directory. It
	 * creates a hashmap containing all the found images and actualize the
	 * ProgressBar for the overall progress with the size of the HashMap as
	 * MaxValue.
	 * 
	 * @param dirname -
	 *                    the source directory as displayed in the sourceTextField
	 * @return true if no error has occured during scan and at least one file
	 *               was found.
	 */
	public boolean findFiles(String dirname) {
		
		File[] dir;
		File source = new File(dirname);

		if (!source.exists()) {
			JOptionPane.showMessageDialog(
				this,
				"Katalog źródłowy nie istnieje",
				"Katalog źródłowy nie istnieje",
				JOptionPane.ERROR_MESSAGE,
				null);
			return false;
		}

		if (source.isFile()) {
			JOptionPane.showMessageDialog(
				this,
				"Źródło musi być katalogiem",
				"Źródło musi być katalogiem!",
				JOptionPane.ERROR_MESSAGE);
			return false;
		}

		dir = source.listFiles(new FileFilter() {
			public boolean accept(File pathname) {
				if (pathname.isFile()) {
					if (!Pattern.matches("^\\..*", pathname.getName()) && Pattern
						.matches(
							"^.*(\\.JPG|\\.JPEG|\\.jpg|\\.jpeg)$",
							pathname.getName())) {
						return true;
					}
				} else if (pathname.isDirectory()) {
					return true;
				}
				return false;
			}

		});

		for (int i = 0; i < dir.length; i++) {

			if (dir[i].isFile()) {
				// Insert File in global list
				files.put(dir[i].getAbsolutePath(), dir[i]);

			} else if (dir[i].isDirectory()) {
				// If isDir then recurse into it
				findFiles(dir[i].toString());
			} else {
				message(
					"<HTML><i>Bum: </i></html>"
						+ dir[i].getName());
			}
		}
			return true;
	}

	public void run() {
		// TODO Auto-generated method stub
		initComponents();
		this.pack();
		this.setVisible(true);

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		// TODO Auto-generated method stub

		if (e.getActionCommand() == "Wyjście") {
			this.exitButtonActionPerformed(e);
		} else if (e.getActionCommand() == "Przetwarzanie") {
			startSortButtonActionPerformed(e);
		} else if (e.getActionCommand() == "Opcje") {
			this.setPropertiesMenuItemActionPerformed(e);
		} else if (e.getActionCommand() == "Jak korzystać") {
			this.usageHelpMenuItemActionPerformed(e);
		} else if (e.getActionCommand() == "O programie") {
			this.aboutHelpMenuItemActionPerformed(e);
//		} else if (e.getActionCommand() == "Help on Database") {
//			this.dbHelpMenuItemActionPerformed(e);
		} else if (e.getActionCommand() == "Ok") {
			jd.setVisible(false);
			jd = null;
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
	 */
	public void stateChanged(ChangeEvent e) {
		// TODO Auto-generated method stub
		repaint();
	}

	public void message(String message) {
		outputTextArea.append(message + "\n");
	}

//	public void setfileLabel(String Label) {
//		fileLabel.setText(Label);
//	}
//	public void setfileProgress(int value) {
//		fileProgress.setValue(value);
//	}
	public void setallProgress(int value) {
		allProgress.setValue(value);
	}
	public void setallProgressMAX(int value) {
		allProgress.setMaximum(value);
	}
	public void loadProperties(String configfile) {
		
		System.err.println("Przeładowanie właściwości: " + configfile);
		//User has provided a configfile, so use it
		BufferedInputStream  is;	
		try {
			is = new BufferedInputStream(new FileInputStream(configfile));
			properties.load(is);
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			System.err.println("Nie znaleziono pliku konfiguracyjnego: " + e1.toString());
			System.exit(1);
		}
		catch (IOException e2) {
			// TODO Auto-generated catch block
			System.err.println("Nie można odnaleźć pliku konfiguracyjnego: " + e2.toString());
			System.exit(1);
		}
		properties.setProperty("PROPERTIESFILE", configfile);
	}

}
